﻿
using System;
using System.Collections.Generic;
using System.Linq;
using Styx;
using Styx.Logic.Combat;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

namespace Altarboy
{
  static class TargetManager
    {

        // Current Player   
        public static LocalPlayer Me { get { return StyxWoW.Me; }}

        #region Add Detection
     
        public static List<WoWUnit> DetectHostileTargets(int range)
        {
            var addList = ObjectManager.GetObjectsOfType<WoWUnit>(false).FindAll(unit =>
                        unit.Guid != Me.Guid &&
                        unit.Distance <= range &&
                        ShouldAttack(unit))
                        .OrderBy(unit => unit.CurrentHealth).ToList();
            return addList;
        }
        #endregion
                
        public static bool IsUnitInRange(WoWUnit unit, double range)
        {
            return (unit != null && unit.Distance < range && unit.InLineOfSightOCD);
        }

        public static bool ShouldAttack(WoWUnit unit)
        {
            if (unit.Name == "Training Dummy" || unit.Name == "Raider's Training Dummy")
            {
                return true;
            }
            return unit.Attackable
                   && !IsCrowdControlled(unit)
                   && unit.IsAlive
                   && unit.Combat
                   && (!unit.IsPlayer || unit.ToPlayer().IsHorde != Me.IsHorde)
                   && !IsMeOrMyGroup(unit)
                   && (IsTargetingMeOrMyGroup(unit) || unit.CreatureType == WoWCreatureType.Totem)
                   && !Styx.Logic.Blacklist.Contains(unit.Guid)
                   && !AltarboyHashes.IsSpecialMobType(unit, AltarboyHashes.MobTypes.Ignore);
        }

      public static int NumOfHostileWithinRange(WoWUnit target, double range) { 

             var mobList = (from o in ObjectManager.ObjectList
                                   where o is WoWUnit && o.Distance <= 50
                                   let unit = o.ToUnit()
                                   where ShouldAttack(unit)
                                   select unit
                                    ).ToList();
          return mobList.Count(unit => target.Location.Distance(unit.Location) <= range);
        }

      public static bool CrowdControllUnitInRange(WoWUnit target, double range)
      {
          var mobList = (from o in ObjectManager.ObjectList
                         where o is WoWUnit && o.Distance <= 50
                         let unit = o.ToUnit()
                         where unit.IsAlive
                         select unit
                        ).ToList();
          return mobList.Any(unit => IsCrowdControlled(unit) && target.Location.Distance(unit.Location) <= range);
      }

      public static bool IsCrowdControlled(WoWUnit unit)
      {
          return unit.GetAllAuras().Any(
              a => a.IsHarmful &&
                   (a.Spell.Mechanic == WoWSpellMechanic.Shackled ||
                    a.Spell.Mechanic == WoWSpellMechanic.Polymorphed ||
                    a.Spell.Mechanic == WoWSpellMechanic.Horrified ||
                    a.Spell.Mechanic == WoWSpellMechanic.Rooted ||
                    a.Spell.Mechanic == WoWSpellMechanic.Frozen ||
                    a.Spell.Mechanic == WoWSpellMechanic.Stunned ||
                    a.Spell.Mechanic == WoWSpellMechanic.Fleeing ||
                    a.Spell.Mechanic == WoWSpellMechanic.Banished ||
                    a.Spell.Mechanic == WoWSpellMechanic.Sapped));
      }

        public static bool IsMeOrMyStuff(WoWUnit unit)
        {
            if (unit == null)
                return false;

            // find topmost unit in CreatedByUnit chain
            while (unit.CreatedByUnit != null)
                unit = unit.CreatedByUnit;

            // check if this unit was created by me
            return unit.IsMe;
        }

        public static bool IsTargetingMeOrMyStuff(WoWUnit unit)
        {
            return unit != null && IsMeOrMyStuff(unit.CurrentTarget);
        }

        public static bool IsMeOrMyGroup(WoWUnit unit)
        {
            if (unit != null)
            {
                // find topmost unit in CreatedByUnit chain
                while (unit.CreatedByUnit != null)
                    unit = unit.CreatedByUnit;

                if (unit.IsMe)
                    return true;

                if (unit.IsPlayer)
                {
                    WoWPlayer p = unit.ToPlayer();
                    if (p.IsHorde == Me.IsHorde && PartyManager.GroupMembers.Contains(unit.ToPlayer()))
                        return true;
                }
            }

            return false;
        }

        public static bool IsTargetingMeOrMyGroup(WoWUnit unit)
        {
            return unit != null && IsMeOrMyGroup(unit.CurrentTarget);
        }


        public enum RaidTargetIcon
        {
            None = 0,
            Star = 1,
            Circle = 2,
            Diamond = 3,
            Triangle = 4,
            Moon = 5,
            Square = 6,
            Cross = 7,
            Skull = 8,
        }
        
       
        //public static void SetRaidTarget(this WoWUnit unit, RaidTargetIcon icon)
        //{
        //    WoWUnit currentTarget = StyxWoW.Me.CurrentTarget;
        //    unit.Target();
        //    Lua.DoString("SetRaidTarget(\"target\", {0});", (int)icon);
        //    currentTarget.Target();
        //}

        public static RaidTargetIcon GetRaidTarget(this WoWUnit unit)
        {
         
            //this is slow as fuck... right now it has to manually target each unit to check it.
            WoWUnit currentTarget = StyxWoW.Me.CurrentTarget;
            unit.Target();
            var icon = Lua.GetReturnVal<int>("return GetRaidTargetIndex(\"target\");", 0);
            currentTarget.Target();

            return icon > 8 || icon < 0 ? RaidTargetIcon.None : (RaidTargetIcon) icon;
        }

        public static Boolean EnemyHasRaidMarker(WoWUnit unit, RaidTargetIcon raidMarker)
        {
            return ShouldAttack(unit) && GetRaidTarget(unit) == raidMarker;
        }
    }

    
}
